package cn.iocoder.yudao.module.product.service.packaging;

import cn.iocoder.yudao.framework.common.util.constant.ConstantUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.api.code.AutoCodeUtilsApi;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.category.ProductCategoryMapper;
import cn.iocoder.yudao.module.product.dal.mysql.cylindertype.CylinderTypeMapper;
import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import cn.iocoder.yudao.module.product.controller.admin.packaging.vo.*;
import cn.iocoder.yudao.module.product.dal.dataobject.packaging.PackagingDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.product.dal.mysql.packaging.PackagingMapper;

import java.time.LocalDateTime;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;

/**
 * 商品包装物 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class PackagingServiceImpl implements PackagingService {

    @Resource
    private PackagingMapper packagingMapper;

    @Resource
    private CylinderTypeMapper cylinderTypeMapper;

    @Resource
    private ProductSkuMapper productSkuMapper;

    @Resource
    private ProductSpuMapper productSpuMapper;

    @Resource
    private ProductCategoryMapper productCategoryMapper;

    @Resource
    private AutoCodeUtilsApi autoCodeUtilsApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createPackaging(PackagingSaveReqVO createReqVO) {
        // 校验名称是否重复
        validatePackagingNameRepeat(createReqVO.getSpuName());
        // 先新增spu商品再新增sku 一对一
        LambdaQueryWrapperX<ProductCategoryDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(ProductCategoryDO ::getParentId, 0 )
                .eq(ProductCategoryDO ::getName, "钢瓶" );
        /*  新增spu  */
        ProductSpuDO productSpuDO = new ProductSpuDO();
        productSpuDO.setCategoryId(productCategoryMapper.selectOne(wrapper) == null ? null : productCategoryMapper.selectOne(wrapper).getId());
        productSpuDO.setName(createReqVO.getSpuName());
        productSpuDO.setPicUrl(createReqVO.getPicUrl());
        // 默认上架
        productSpuDO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());

        //  ======== 设置spu无效值  =========//
        // 单位： 件
        productSpuDO.setUnit(1);
        productSpuDO.setDeliveryTemplateType(-1);
        productSpuDO.setUseContainer(-1);
        productSpuDO.setOneItemOneCode(-1);
        productSpuDO.setSpuCode(String.valueOf(System.currentTimeMillis()));
        // ======= 设置spu无效值结束  ==========//

        //生成spuCode
        String spuCode = autoCodeUtilsApi.getSpuAndSkuCode(ConstantUtil.SPU);
        productSpuDO.setSpuCode(ConstantUtil.SPU+spuCode);

        productSpuMapper.insert(productSpuDO);
        /*  新增sku  */
        ProductSkuDO productSkuDO = new ProductSkuDO();
        productSkuDO.setSpuId(productSpuDO.getId());
        // type = 1 = 包装物
        productSkuDO.setProductType(1);
        productSkuDO.setCreateTime(LocalDateTime.now());
        productSkuDO.setPicUrl(createReqVO.getPicUrl());
        productSkuDO.setSkuCode(String.valueOf(System.currentTimeMillis()));

        String code =autoCodeUtilsApi.getSpuAndSkuCode(spuCode);
        productSkuDO.setSkuCode(ConstantUtil.SKU+spuCode+code);
        productSkuMapper.insert(productSkuDO);

        // 插入
        PackagingDO packaging = BeanUtils.toBean(createReqVO, PackagingDO.class);
        // 校验押金、租金上限下限是否符合基准值
//        validateDepositOrderPriceConf(packaging);

        packaging.setCreateTime(LocalDateTime.now());
        packaging.setSkuId(productSkuDO.getId());
        packagingMapper.insert(packaging);


        // 返回
        return packaging.getId();
    }

    // 校验押金 / 租金 的基准值上限下限
    private void validateDepositOrderPriceConf(PackagingDO dto) {
        // 押金超过上限
        if (dto.getDepositUpperPr().compareTo(dto.getDepositReferencePr()) > 0){
            throw exception(DEPOSIT_ORDER_PRICE_DEPOSIT_UPPER, dto.getDepositReferencePr());
        }
        // 押金低于下限
        if (dto.getDepositLowerPr().compareTo(dto.getDepositLowerPr()) < 0){
            throw exception(DEPOSIT_ORDER_PRICE_OEPOSIT_LOWER, dto.getDepositReferencePr());
        }
        // 如果收取租金
        if (dto.getIsRent() == 0) {
            // 租金超过上限
            if (dto.getRentUpperPr().compareTo(dto.getRentReferencePr()) > 0){
                throw exception(DEPOSIT_ORDER_RENT_UPPER, dto.getRentReferencePr());
            }
            // 租金低于下限
            if (dto.getRentLowerPr().compareTo(dto.getRentLowerPr()) < 0){
                throw exception(DEPOSIT_ORDER_RENT_LOWER, dto.getRentReferencePr());
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePackaging(PackagingSaveReqVO updateReqVO) {
        // 校验存在
        validatePackagingExists(updateReqVO.getId());

        PackagingDO packagingDO = packagingMapper.selectById(updateReqVO.getId());
        if (!packagingDO.getSpuName().equals(updateReqVO.getSpuName())){
            // 校验名称是否重复
            validatePackagingNameRepeat(updateReqVO.getSpuName());
            // 更新spu表字段name名称

            ProductSpuDO productSpuDO = new ProductSpuDO();
            productSpuDO.setId(productSkuMapper.selectById(updateReqVO.getSkuId()).getSpuId());
            productSpuDO.setName(updateReqVO.getSpuName());
            productSpuMapper.updateById(productSpuDO);
        }

        // 更新
        PackagingDO updateObj = BeanUtils.toBean(updateReqVO, PackagingDO.class);
        packagingMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePackaging(Integer id) {
        // 校验存在
        validatePackagingExists(id);
        // 删除
        packagingMapper.deleteById(id);

        PackagingDO packagingDO = packagingMapper.selectById(id);
        // 删除spu记录
        productSpuMapper.deleteById(productSkuMapper.selectById(packagingDO.getSkuId()).getSpuId());
        // 删除sku记录
        productSkuMapper.deleteById(packagingDO.getSkuId());
    }

    private void validatePackagingExists(Integer id) {
        if (packagingMapper.selectById(id) == null) {
            throw exception(PACKAGING_NOT_EXISTS);
        }
    }
    private void validatePackagingNameRepeat(String name) {
        LambdaQueryWrapperX<PackagingDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(PackagingDO ::getDeleted, 0)
                .eq(PackagingDO ::getSpuName, name );
        if (null != packagingMapper.selectOne(wrapper)) {
            throw exception(PACKAGING_NAME_REPEAT);
        }
    }

    @Override
    public PackagingDO getPackaging(Integer id) {
        return packagingMapper.selectById(id);
    }

    @Override
    public PageResult<PackagingDO> getPackagingPage(PackagingPageReqVO pageReqVO) {
        List<PackagingDO> packagingPage = packagingMapper.getPackagingPage(pageReqVO);
        PageResult<PackagingDO> result = new PageResult<>(BeanUtils.toBean(packagingPage,PackagingDO.class), (long) packagingPage.size());

        return result;
    }

    @Override
    public List<PackagingDO> getPackagingList() {
        LambdaQueryWrapperX<PackagingDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(PackagingDO ::getDeleted, 0);
        return packagingMapper.selectList(wrapper);
    }

    @Override
    public PackagingDO getPackagingBySkuId(Long id) {
        LambdaQueryWrapperX<PackagingDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(PackagingDO ::getDeleted, 0);
        wrapper.eq(PackagingDO::getSkuId,id);
        return packagingMapper.selectOne(wrapper);
    }

}